﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Wechat.Util.Encryp
{
    /// <summary>
    /// 加密解密工具类
    /// </summary>
    public static class EncryptUtil
    {
        #region Fields

        private static readonly byte[] _DESKeyBytes = { 0xa1, 0xd2, 0xf3, 0xb4, 0xc5, 0xe6, 0x4a, 0x02 };
        private static readonly byte[] _DESIVBytes = { 0xf3, 0x91, 0xd6, 0xff, 0x32, 0x1f, 0x4c, 0x12 };
        private static readonly byte[] _AESKeyBytes = { 0xf3, 0x91, 0xd6, 0xff, 0x32, 0x1f, 0x4a, 0x02, 0xe4, 0x88, 0x25, 0x90, 0x72, 0xb3, 0xa7, 0x11 };
        private static readonly byte[] _AESIVBytes = { 0x15, 0x33, 0x21, 0x9f, 0xb6, 0xdc, 0xaf, 0xd8, 0xd4, 0x37, 0x5f, 0x95, 0x13, 0xe4, 0x72, 0xdd };
        private const int SALT_BYTES_LENGTH = 16;   // 盐值长度

        #endregion

        #region DES 加密/解密

        /// <summary>
        /// DES 加密
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string DESEncrypt(string input)
        {
            return DESEncrypt(input, _DESKeyBytes, _DESIVBytes);
        }

        /// <summary>
        /// DES 加密
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string DESEncrypt(string input, byte[] key, byte[] iv)
        {
            DESCryptoServiceProvider csp = new DESCryptoServiceProvider();
            using (ICryptoTransform ct = csp.CreateEncryptor(key, iv))
            using (MemoryStream ms = new MemoryStream())
            using (CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write))
            {
                byte[] bytes = Encoding.UTF8.GetBytes(input);
                cs.Write(bytes, 0, bytes.Length);
                cs.Write(GetSaltBytes(), 0, SALT_BYTES_LENGTH); // 增加随即生成的盐值，保证每次加密的结果不同
                cs.FlushFinalBlock();
                return Convert.ToBase64String(ms.ToArray());
            }
        }

        /// <summary>
        /// DES 解密
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string DESDecrypt(string input)
        {
            return DESDecrypt(input, _DESKeyBytes, _DESIVBytes);
        }

        /// <summary>
        /// DES 解密
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string DESDecrypt(string input, byte[] key, byte[] iv)
        {
            DESCryptoServiceProvider csp = new DESCryptoServiceProvider();
            using (ICryptoTransform ct = csp.CreateDecryptor(key, iv))
            using (MemoryStream ms = new MemoryStream())
            using (CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write))
            {
                byte[] bytes = Convert.FromBase64String(input);
                cs.Write(bytes, 0, bytes.Length);
                cs.FlushFinalBlock();

                // 去除盐值部分
                bytes = ms.ToArray();
                byte[] result = new byte[bytes.Length - SALT_BYTES_LENGTH];
                Buffer.BlockCopy(bytes, 0, result, 0, result.Length);

                return Encoding.UTF8.GetString(result);
            }
        }

        #endregion

        #region MD5

        /// <summary>
        /// MD5加密
        /// </summary>
        /// <param name="input">待加密字串</param>
        /// <returns>加密后的字串</returns>
        public static string MD5Encrypt(string input)
        {
            return MD5Encrypt(input, 0);
        }

        /// <summary>
        /// MD5加密
        /// </summary>
        /// <param name="input">待加密字串</param>
        /// <param name="length">16或32值之一，其它则采用.net默认MD5加密算法</param>
        /// <returns>加密后的字串</returns>
        public static string MD5Encrypt(string input, int length)
        {
            byte[] buffer = Encoding.ASCII.GetBytes(input);
            byte[] hashValue = MD5.Create().ComputeHash(buffer);

            string result;
            switch (length)
            {
                case 16:
                    result = BitConverter.ToString(hashValue, 4, 8).Replace("-", "");
                    break;
                case 32:
                    result = BitConverter.ToString(hashValue, 0, 16).Replace("-", "");
                    break;
                default:
                    result = BitConverter.ToString(hashValue).Replace("-", "");
                    break;
            }

            return result;
        }


        /// <summary>
        /// 获取MD5值（小写形式）
        /// </summary>
        /// <param name="input"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string MD5_Lower(string input, Encoding encoding)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] bytes = md5.ComputeHash(encoding.GetBytes(input));
            return BitConverter.ToString(bytes).Replace("-", "").ToLower();
        }

        #endregion

        #region Common

        private static byte[] GetSaltBytes()
        {
            byte[] bytes = new byte[SALT_BYTES_LENGTH];
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            rng.GetBytes(bytes);

            return bytes;
        }

        #endregion

        #region RC4解密
        public static String RC4Decrypt(string msg, string rc4_key)
        {
            var data = Convert.FromBase64String(msg);
            var bytes = RC4Util.Decrypt(data, rc4_key);
            return Encoding.UTF8.GetString(bytes);
        }
        #endregion

        #region MD5加密
        /// <summary>   
        /// MD5加密   
        /// </summary>   
        /// <param name="strSource">需要加密的字符串</param>   
        /// <returns>MD5加密后的字符串</returns>   
        public static string Md5Encrypt(string strSource)
        {
            //把字符串放到byte数组中   
            byte[] bytIn = System.Text.Encoding.Default.GetBytes(strSource);
            //建立加密对象的密钥和偏移量           
            byte[] iv = { 102, 16, 93, 156, 78, 4, 218, 32 };//定义偏移量   
            byte[] key = { 55, 103, 246, 79, 36, 99, 167, 3 };//定义密钥   
            //实例DES加密类   
            DESCryptoServiceProvider mobjCryptoService = new DESCryptoServiceProvider();
            mobjCryptoService.Key = iv;
            mobjCryptoService.IV = key;
            ICryptoTransform encrypto = mobjCryptoService.CreateEncryptor();
            //实例MemoryStream流加密密文件   
            System.IO.MemoryStream ms = new System.IO.MemoryStream();
            CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Write);
            cs.Write(bytIn, 0, bytIn.Length);
            cs.FlushFinalBlock();
            return System.Convert.ToBase64String(ms.ToArray());
        }


        /// <summary>   
        /// MD5解密   
        /// </summary>   
        /// <param name="Source">需要解密的字符串</param>   
        /// <returns>MD5解密后的字符串</returns>   
        public static string Md5Decrypt(string Source)
        {
            //将解密字符串转换成字节数组   
            byte[] bytIn = System.Convert.FromBase64String(Source);
            //给出解密的密钥和偏移量，密钥和偏移量必须与加密时的密钥和偏移量相同   
            byte[] iv = { 102, 16, 93, 156, 78, 4, 218, 32 };//定义偏移量   
            byte[] key = { 55, 103, 246, 79, 36, 99, 167, 3 };//定义密钥   
            DESCryptoServiceProvider mobjCryptoService = new DESCryptoServiceProvider();
            mobjCryptoService.Key = iv;
            mobjCryptoService.IV = key;
            //实例流进行解密   
            System.IO.MemoryStream ms = new System.IO.MemoryStream(bytIn, 0, bytIn.Length);
            ICryptoTransform encrypto = mobjCryptoService.CreateDecryptor();
            CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Read);
            StreamReader strd = new StreamReader(cs, Encoding.Default);
            return strd.ReadToEnd();
        }


        #endregion


        #region 动态加密


        private static byte[] s_bytKey;
        static EncryptUtil()
        {
            s_bytKey = new byte[] { 0xa1, 0xb2, 0xc3, 0xd4, 0xe5, 0x16, 0x27, 0x38, 0x49, 80, 0x61, 0x72, 0x83, 0x94, 0xa5, 0xb6 };
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="text"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string PutBykey(string text, string key)
        {
            byte[] buffer = new byte[text.Length];
            byte[] bytes = Encoding.UTF8.GetBytes(DisposeId(key));
            RijndaelManaged managed = new RijndaelManaged();
            buffer = Convert.FromBase64String(text);

            MemoryStream stream = new MemoryStream();
            CryptoStream stream2 = new CryptoStream(stream, managed.CreateDecryptor(bytes, s_bytKey), CryptoStreamMode.Write);
            stream2.Write(buffer, 0, buffer.Length);
            stream2.FlushFinalBlock();
            Encoding encoding = new UTF8Encoding();
            return encoding.GetString(stream.ToArray());
        }

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="text"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetByKey(string text, string key)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(text);
            byte[] rgbKey = Encoding.UTF8.GetBytes(DisposeId(key));
            RijndaelManaged managed = new RijndaelManaged();
            MemoryStream stream = new MemoryStream();
            CryptoStream stream2 = new CryptoStream(stream, managed.CreateEncryptor(rgbKey, s_bytKey), CryptoStreamMode.Write);
            stream2.Write(bytes, 0, bytes.Length);
            stream2.FlushFinalBlock();
            return Convert.ToBase64String(stream.ToArray());
        }


        /// <summary>
        /// 处理Id，转变为加密key
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static string DisposeId(string id)
        {
            string strValue = "";
            for (int i = 0; i < 9 - id.Length; i++)
            {
                strValue += i;
            }
            return id.ToString() + strValue;
        }



        #endregion

    }
}
